/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.widgets; import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.*; import java.util.*; /** * Instances of this class allow the user to select a font * from all available fonts in the system. * <dl> * <dt><b>Styles:</b></dt> * <dd>(none)</dd> * <dt><b>Events:</b></dt> * <dd>(none)</dd> * </dl> * <p> * IMPORTANT: This class is <em>not</em> intended to be subclassed. * </p> * * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Dialog tab</a> * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> * @noextend This class is not intended to be subclassed by clients. */ public class FontDialog extends Dialog { private FontData [] fontData; private FontData currentFontData; private Font sampleFont; // the displayed sample font private Color sampleColor; // the displayed sample color private RGB rgb; private boolean okSelected = false; private boolean ignoreEvents = false; /* * Table containing all available fonts as FontData objects. * The table is structured as a series of embedded Hashtables as follows: * <br>characterRegistryName -> faceName -> extendedStyle -> size -> style */ private Hashtable characterSets = new Hashtable (); // widgets private Shell shell; private List fontSetList; private List charSetList, faceNameList, extStyleList; private List fontStyleList, fontSizeList; private Label sampleLabel; private Button upButton, downButton, newButton, removeButton; private Button okButton, cancelButton, colorButton; // constants private static final String TEXT_SAMPLE = "AaBbYyZz"; private static String SCALABLE_SIZES []; private static final int DEFAULT_SIZE = 14; private static final String DEFAULT_STYLE = "medium"; private static final Integer SCALABLE_KEY = new Integer (0); private static final int LIST_WIDTH = 200; private static final int EXTSTYLE_WIDTH = 150; private static final int LIST_HEIGHT = 150; private static final int SAMPLE_HEIGHT = 75; private static final String PREFIX_ISO8859 = "iso8859"; private static final String PREFIX_ISO646 = "iso646"; private static final String PREFIX_UNICODE = "ucs"; private static final String PREFIX_JAPANESE = "jis"; private static final String PREFIX_SIMPLIFIEDCHINESE = "gb"; private static final String PREFIX_TRADITIONALCHINESE = "cns"; private static final String PREFIX_KOREAN = "ks"; private static final String [] ISO_CHARSETS = new String [] { "", // 0 undefined SWT.getMessage ("SWT_Charset_Western"), SWT.getMessage ("SWT_Charset_EastEuropean"), SWT.getMessage ("SWT_Charset_SouthEuropean"), SWT.getMessage ("SWT_Charset_NorthEuropean"), SWT.getMessage ("SWT_Charset_Cyrillic"), SWT.getMessage ("SWT_Charset_Arabic"), SWT.getMessage ("SWT_Charset_Greek"), SWT.getMessage ("SWT_Charset_Hebrew"), SWT.getMessage ("SWT_Charset_Turkish"), SWT.getMessage ("SWT_Charset_Nordic"), SWT.getMessage ("SWT_Charset_Thai"), "", // 12 undefined SWT.getMessage ("SWT_Charset_BalticRim"), SWT.getMessage ("SWT_Charset_Celtic"), SWT.getMessage ("SWT_Charset_Euro"), SWT.getMessage ("SWT_Charset_Romanian") }; static { SCALABLE_SIZES = new String [69]; for (int i = 0; i < 69; i++) { SCALABLE_SIZES [i] = String.valueOf (i + 4); } } /** * Constructs a new instance of this class given only its parent. * * @param parent a shell which will be the parent of the new instance * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> */ public FontDialog (Shell parent) { this (parent, SWT.APPLICATION_MODAL); } /** * Constructs a new instance of this class given its parent * and a style value describing its behavior and appearance. * <p> * The style value is either one of the style constants defined in * class <code>SWT</code> which is applicable to instances of this * class, or must be built by <em>bitwise OR</em>'ing together * (that is, using the <code>int</code> "|" operator) two or more * of those <code>SWT</code> style constants. The class description * lists the style constants that are applicable to the class. * Style bits are also inherited from superclasses. * </p> * * @param parent a shell which will be the parent of the new instance * @param style the style of dialog to construct * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> */ public FontDialog (Shell parent, int style) { super (parent, checkStyle (parent, style)); checkSubclass (); } /** * Add the fonts found in 'fonts' to the list of fonts. * Fonts are stored by character set and face name. For each character * set/face name combination there is one FontExtStyles object that * captures the different extended styles and the sizes and styles * available for that extended style. */ void addFonts (FontData fonts []) { for (int i = 0; i < fonts.length; i++) { FontData font = fonts [i]; String charSetName = getTranslatedCharSet (font, true); Hashtable charSet = (Hashtable) characterSets.get (charSetName); if (charSet == null) { charSet = new Hashtable (9); characterSets.put (charSetName, charSet); } String faceName = getTranslatedFaceName (font); Hashtable faceSet = (Hashtable) charSet.get (faceName); if (faceSet == null) { faceSet = new Hashtable (9); charSet.put (faceName, faceSet); } String extStyleName = font.addStyle; Hashtable extStyleSet = (Hashtable) faceSet.get (extStyleName); if (extStyleSet == null) { extStyleSet = new Hashtable (9); faceSet.put (extStyleName, extStyleSet); } Integer sizeValue = new Integer (font.getHeight ()); Hashtable sizeSet = (Hashtable) extStyleSet.get (sizeValue); if (sizeSet == null) { sizeSet = new Hashtable (9); extStyleSet.put (sizeValue, sizeSet); } String style = font.weight; sizeSet.put (style,font); } } void centerListIndex (List list, int index) { int visibleItems = list.getSize ().y / list.getItemHeight (); int topIndex = Math.max (0, index - visibleItems / 2); list.setTopIndex (topIndex); } FontData copyFontData (FontData data) { FontData result = new FontData (); result.addStyle = data.addStyle; result.averageWidth = data.averageWidth; result.characterSetName = data.characterSetName; result.characterSetRegistry = data.characterSetRegistry; result.fontFamily = data.fontFamily; result.foundry = data.foundry; result.horizontalResolution = data.horizontalResolution; result.pixels = data.pixels; result.points = data.points; result.setWidth = data.setWidth; result.slant = data.slant; result.spacing = data.spacing; result.verticalResolution = data.verticalResolution; result.weight = data.weight; return result; } void createButtons (Composite parent) { int buttonAlignment = GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING; okButton = new Button (parent, SWT.PUSH); okButton.setText (SWT.getMessage ("SWT_OK")); okButton.setLayoutData (new GridData (buttonAlignment)); shell.setDefaultButton (okButton); cancelButton = new Button (parent, SWT.PUSH); cancelButton.setText (SWT.getMessage ("SWT_Cancel")); cancelButton.setLayoutData (new GridData (buttonAlignment)); colorButton = new Button (parent, SWT.PUSH); colorButton.setText (SWT.getMessage ("SWT_Color")); colorButton.setLayoutData (new GridData (buttonAlignment)); } void createControls (Composite parent) { Composite composite = new Composite (parent, SWT.NONE); GridLayout layout = new GridLayout (); layout.numColumns = 2; composite.setLayout (layout); Composite controls = new Composite (composite, SWT.NONE); layout = new GridLayout (); layout.marginHeight = layout.marginWidth = 0; layout.numColumns = 3; controls.setLayout (layout); // labels row (1) new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Character_set") + ":"); new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Font") + ":"); new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Extended_style") + ":"); // lists row (2) charSetList = new List (controls, SWT.V_SCROLL | SWT.BORDER); GridData gridData = new GridData (GridData.FILL_HORIZONTAL); gridData.heightHint = LIST_HEIGHT; gridData.widthHint = LIST_WIDTH; charSetList.setLayoutData (gridData); faceNameList = new List (controls, SWT.V_SCROLL | SWT.BORDER); gridData = new GridData (GridData.FILL_HORIZONTAL); gridData.heightHint = LIST_HEIGHT; gridData.widthHint = LIST_WIDTH; faceNameList.setLayoutData (gridData); extStyleList = new List (controls, SWT.V_SCROLL | SWT.MULTI | SWT.BORDER); gridData = new GridData (GridData.FILL_HORIZONTAL); gridData.heightHint = LIST_HEIGHT; gridData.widthHint = EXTSTYLE_WIDTH; extStyleList.setLayoutData (gridData); // labels row (3) new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Size") + ":"); new Label (controls, SWT.NONE).setText (SWT.getMessage ("SWT_Style") + ":"); new Label (controls, SWT.NONE); // filler // lists row (4) fontSizeList = new List (controls, SWT.V_SCROLL | SWT.BORDER); gridData = new GridData (GridData.FILL_HORIZONTAL); gridData.heightHint = LIST_HEIGHT; gridData.widthHint = LIST_WIDTH; fontSizeList.setLayoutData (gridData); fontStyleList = new List (controls, SWT.V_SCROLL | SWT.BORDER); gridData = new GridData (GridData.FILL_HORIZONTAL); gridData.heightHint = LIST_HEIGHT; gridData.widthHint = LIST_WIDTH; fontStyleList.setLayoutData (gridData); new Label (controls, SWT.NONE); // filler // font sets group Group fontSetGroup = new Group (controls, SWT.NONE); fontSetGroup.setText(SWT.getMessage ("SWT_FontSet")); layout = new GridLayout (); layout.numColumns = 2; fontSetGroup.setLayout (layout); GridData data = new GridData (GridData.FILL_BOTH); data.horizontalSpan = 3; fontSetGroup.setLayoutData (data); fontSetList = new List (fontSetGroup, SWT.V_SCROLL | SWT.BORDER); data = new GridData (GridData.FILL_BOTH); data.grabExcessHorizontalSpace = true; fontSetList.setLayoutData (data); Composite buttonsGroup = new Composite (fontSetGroup, SWT.NONE); layout = new GridLayout (); layout.numColumns = 3; layout.makeColumnsEqualWidth = false; layout.marginHeight = layout.marginWidth = 0; layout.horizontalSpacing = layout.verticalSpacing = 0; buttonsGroup.setLayout (layout); Composite upDownButtonsGroup = new Composite (buttonsGroup, SWT.NONE); layout = new GridLayout (); layout.marginHeight = layout.marginWidth = 0; layout.horizontalSpacing = layout.verticalSpacing = 0; upDownButtonsGroup.setLayout(layout); int buttonAlignment = GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING; upButton = new Button (upDownButtonsGroup, SWT.PUSH); upButton.setLayoutData (new GridData (buttonAlignment)); upButton.setText (SWT.getMessage ("SWT_Up")); downButton = new Button (upDownButtonsGroup, SWT.PUSH); downButton.setLayoutData (new GridData (buttonAlignment)); downButton.setText (SWT.getMessage ("SWT_Down")); new Label (buttonsGroup, SWT.SEPARATOR | SWT.VERTICAL); Composite newRemoveButtonsGroup = new Composite (buttonsGroup, SWT.NONE); layout = new GridLayout (); layout.marginHeight = layout.marginWidth = 0; layout.horizontalSpacing = layout.verticalSpacing = 0; newRemoveButtonsGroup.setLayout(layout); newButton = new Button (newRemoveButtonsGroup, SWT.PUSH); newButton.setLayoutData (new GridData (buttonAlignment)); newButton.setText (SWT.getMessage ("SWT_NewFont")); removeButton = new Button (newRemoveButtonsGroup, SWT.PUSH); removeButton.setLayoutData (new GridData (buttonAlignment)); removeButton.setText (SWT.getMessage ("SWT_Remove")); // font sample group Group sampleGroup = new Group (controls, SWT.NONE); sampleGroup.setText (SWT.getMessage ("SWT_Sample")); gridData = new GridData (); gridData.heightHint = SAMPLE_HEIGHT; gridData.horizontalSpan = 3; gridData.horizontalAlignment = GridData.FILL; sampleGroup.setLayoutData (gridData); layout = new GridLayout (); layout.marginWidth = 10; layout.marginHeight = 10; sampleGroup.setLayout (layout); sampleLabel = new Label (sampleGroup, SWT.CENTER); sampleLabel.setText (TEXT_SAMPLE); gridData = new GridData (); gridData.grabExcessHorizontalSpace = true; gridData.grabExcessVerticalSpace = true; gridData.verticalAlignment = GridData.FILL; gridData.horizontalAlignment = GridData.FILL; sampleLabel.setLayoutData (gridData); Composite okCancelGroup = new Composite (composite, SWT.NONE); layout = new GridLayout (); layout.marginHeight = layout.marginWidth = layout.verticalSpacing = 0; okCancelGroup.setLayout (layout); okCancelGroup.setLayoutData (new GridData (GridData.VERTICAL_ALIGN_BEGINNING)); createButtons (okCancelGroup); } Hashtable getExtStyles (String charsetName, String faceName) { Hashtable faces = getFaces (charsetName); if (faces == null) return null; return (Hashtable) faces.get (faceName); } Hashtable getFaces (String charsetName) { return (Hashtable) getFonts ().get (charsetName); } /** * Returns a FontData object describing the font that was * selected in the dialog, or null if none is available. * * @return the FontData for the selected font, or null * @deprecated use #getFontList () */ public FontData getFontData () { if (fontData != null && fontData.length > 0) { return fontData [0]; } return null; } FontData getFontData (String charsetName, String faceName, String extStyle, int size, String style) { Hashtable styles = getStyles (charsetName, faceName, extStyle, size); if (styles == null) return null; return (FontData) styles.get (style); } /** * Returns a FontData set describing the font that was * selected in the dialog, or null if none is available. * * @return the FontData for the selected font, or null * @since 2.1.1 */ public FontData [] getFontList () { return fontData; } /** * Returns the collection of fonts that are displayed by the * receiver. * See the class definition for an explanation of the structure * of the returned Hashtable. */ Hashtable getFonts () { return characterSets; } String getListSelection (List list) { String [] selection = list.getSelection (); if (selection.length > 0) return selection [0]; return ""; } /** * Returns an RGB describing the color that was selected * in the dialog, or null if none is available. * * @return the RGB value for the selected color, or null * * @see PaletteData#getRGBs * * @since 2.1 */ public RGB getRGB () { return rgb; } /** * Returns a FontData object that can be used to load the selected * font. */ FontData getSelectionFontData () { String charSetName = getListSelection (charSetList); String faceName = getListSelection (faceNameList); String extStyle = getListSelection (extStyleList); int size = DEFAULT_SIZE; try { size = Integer.valueOf (getListSelection (fontSizeList)).intValue (); if (size < 1) size = DEFAULT_SIZE; } catch (NumberFormatException e) { /* * This block is purposely left empty since a default * value is already specified above. */ } String style = getListSelection (fontStyleList); FontData result = getFontData (charSetName, faceName, extStyle, size, style); if (result != null) { result = copyFontData (result); } else { /* * One or more of the dialog's widgets contain custom typed values. * Create a FontData that mirrors these values so that the Font created * below will try to find the best match. */ result = new FontData (); result.characterSetRegistry = charSetName; result.setName (faceName); result.addStyle = extStyle; result.weight = style; } result.setHeight (size); return result; } Hashtable getSizes (String charsetName, String faceName, String extStyle) { Hashtable extStyles = getExtStyles (charsetName, faceName); if (extStyles == null) return null; return (Hashtable) extStyles.get (extStyle); } Hashtable getStyles (String charsetName, String faceName, String extStyle, int size) { Hashtable sizes = getSizes (charsetName, faceName, extStyle); if (sizes == null) return null; Hashtable result = (Hashtable) sizes.get (new Integer (size)); if (result == null) result = (Hashtable) sizes.get (SCALABLE_KEY); return result; } /** * Returns the character set found in 'fontData' prefixed * with a string explaining the character set. */ String getTranslatedCharSet (FontData fontData, boolean includeDescription) { String characterSet = fontData.characterSetRegistry; String translatedCharSet = null; if (characterSet.startsWith (PREFIX_ISO8859)) { int charSetName = 1; try { charSetName = Integer.valueOf (fontData.characterSetName).intValue (); } catch (NumberFormatException e) { /* * This block is purposely left empty since a default * value is already specified above. */ } characterSet = PREFIX_ISO8859 + "-" + charSetName; if (charSetName < ISO_CHARSETS.length) { translatedCharSet = ISO_CHARSETS [charSetName]; } } else if (characterSet.startsWith (PREFIX_ISO646)) { translatedCharSet = SWT.getMessage("SWT_Charset_ASCII"); } else if (characterSet.startsWith (PREFIX_UNICODE)) { translatedCharSet = SWT.getMessage("SWT_Charset_Unicode"); } else if (characterSet.startsWith (PREFIX_JAPANESE)) { translatedCharSet = SWT.getMessage("SWT_Charset_Japanese"); } else if (characterSet.startsWith (PREFIX_SIMPLIFIEDCHINESE)) { translatedCharSet = SWT.getMessage("SWT_Charset_SimplifiedChinese"); } else if (characterSet.startsWith (PREFIX_TRADITIONALCHINESE)) { translatedCharSet = SWT.getMessage("SWT_Charset_TraditionalChinese"); } else if (characterSet.startsWith (PREFIX_KOREAN)) { translatedCharSet = SWT.getMessage("SWT_Charset_Korean"); } if (includeDescription && translatedCharSet != null) { translatedCharSet = characterSet + " (" + translatedCharSet + ')'; } else { translatedCharSet = characterSet; } return translatedCharSet; } /** * Returns the face name as specified in FontData.familyName followed by * the foundry set in parantheses if available. * We display the face name first so that the list sorts the fonts by * face name, not by foundry. Users generally want to select fonts based * on the face name and not by foundry. Once they've found the desired * face name in the list they can compare the font variations from * different foundries if available. */ String getTranslatedFaceName (FontData fontData) { StringBuffer faceNameBuffer; if (fontData.foundry != null && fontData.foundry.length () > 0) { faceNameBuffer = new StringBuffer (fontData.fontFamily); faceNameBuffer.append (" ("); faceNameBuffer.append (fontData.foundry); faceNameBuffer.append (')'); } else { faceNameBuffer = new StringBuffer (fontData.getName ()); } return faceNameBuffer.toString (); } /** * Handle the events the receiver is listening to. * List selections cause the downstream lists to be initialized * with font data and the sample text to be updated. */ void handleEvent (Event event) { if (ignoreEvents) return; if (event.widget instanceof List) { List list = (List) event.widget; String text = getListSelection (list); int oldSelectIndex = ((Integer)list.getData ()).intValue (); int newSelectIndex = list.indexOf (text); if (oldSelectIndex != newSelectIndex || newSelectIndex == -1) { ignoreEvents = true; if (list == charSetList) initFaceNameList (); else if (list == faceNameList) initExtStyleList (); else if (list == extStyleList) initSizeList (); else if (list == fontSizeList) initStyleList (); else if (event.widget == fontSetList) { currentFontData = fontData [fontSetList.getSelectionIndex ()]; setFontControls (currentFontData); updateButtonEnablements (); } updateSampleFont (); updateFontList (); list.setData (new Integer (newSelectIndex)); if (newSelectIndex != -1) { list.select (newSelectIndex); } ignoreEvents = false; } return; } if (event.widget instanceof Button) { if (event.widget == okButton) { okSelected = true; shell.close (); } else if (event.widget == cancelButton) { okSelected = false; shell.close (); } else if (event.widget == colorButton) { ColorDialog colorDialog = new ColorDialog (shell, SWT.NONE); colorDialog.setRGB (rgb); RGB newRgb = colorDialog.open (); if (newRgb != null) { rgb = newRgb; updateSampleColor (); } } else if (event.widget == newButton) { FontData [] newFontData = new FontData [fontData.length + 1]; System.arraycopy (fontData, 0, newFontData, 0, fontData.length); FontData source = fontData [fontSetList.getSelectionIndex ()]; FontData newFd = copyFontData (source); newFontData [newFontData.length - 1] = newFd; this.fontData = newFontData; updateFontList (); fontSetList.select (newFontData.length - 1); fontSetList.setData (new Integer (newFontData.length - 1)); fontSetList.showSelection(); updateButtonEnablements (); } else if (event.widget == removeButton) { int selectionIndex = fontSetList.getSelectionIndex (); FontData [] newFontData = new FontData [fontData.length - 1]; System.arraycopy (fontData, 0, newFontData, 0, selectionIndex); System.arraycopy (fontData, selectionIndex + 1, newFontData, selectionIndex, newFontData.length - selectionIndex); fontData = newFontData; updateFontList (); updateButtonEnablements (); setFontControls (fontData [fontSetList.getSelectionIndex ()]); } else if (event.widget == upButton) { int selectionIndex = fontSetList.getSelectionIndex (); FontData temp = fontData [selectionIndex]; fontData [selectionIndex] = fontData [selectionIndex - 1]; fontData [selectionIndex - 1] = temp; fontSetList.select (selectionIndex - 1); fontSetList.setData (new Integer (selectionIndex - 1)); updateFontList (); updateButtonEnablements (); } else if (event.widget == downButton) { int selectionIndex = fontSetList.getSelectionIndex (); FontData temp = fontData [selectionIndex]; fontData [selectionIndex] = fontData [selectionIndex + 1]; fontData [selectionIndex + 1] = temp; fontSetList.select (selectionIndex + 1); fontSetList.setData (new Integer (selectionIndex + 1)); updateFontList (); updateButtonEnablements (); } } } void hookListeners () { Listener listener = new Listener () { public void handleEvent (Event event) { FontDialog.this.handleEvent (event); } }; okButton.addListener (SWT.Selection, listener); cancelButton.addListener (SWT.Selection, listener); colorButton.addListener (SWT.Selection, listener); charSetList.addListener (SWT.Selection, listener); faceNameList.addListener (SWT.Selection, listener); fontStyleList.addListener (SWT.Selection, listener); extStyleList.addListener (SWT.Selection, listener); fontSizeList.addListener (SWT.Selection, listener); newButton.addListener (SWT.Selection, listener); removeButton.addListener (SWT.Selection, listener); upButton.addListener (SWT.Selection, listener); downButton.addListener (SWT.Selection, listener); fontSetList.addListener (SWT.Selection, listener); } /** * Initialize the extended styles list with the extended styles * available for the selected font. * Downstream lists are initialized as well (style and size). */ void initExtStyleList () { String oldSelect = getListSelection (extStyleList); extStyleList.removeAll (); String characterSet = getListSelection (charSetList); String faceName = getListSelection (faceNameList); Hashtable extStyles = getExtStyles (characterSet, faceName); setItemsSorted (extStyleList, extStyles); int selectIndex = extStyleList.indexOf (oldSelect); extStyleList.select (selectIndex); extStyleList.setData (new Integer (selectIndex)); centerListIndex (extStyleList, selectIndex); initSizeList (); } /** * Initialize the face name list with all font names * available in the selected character set. * Downstream lists are initialized as well (extended style). */ void initFaceNameList () { String oldSelect = getListSelection (faceNameList); faceNameList.removeAll (); String charSetText = getListSelection (charSetList); if (charSetText.length () == 0) return; Hashtable faceNames = getFaces (charSetText); setItemsSorted (faceNameList, faceNames); int selectIndex = faceNameList.indexOf (oldSelect); selectIndex = Math.max (0, selectIndex); faceNameList.select (selectIndex); faceNameList.setData (new Integer (selectIndex)); centerListIndex (faceNameList, selectIndex); initExtStyleList (); } /** * Initialize the widgets of the receiver with the data of * all installed fonts. If the user specified a default font * preselect that font in the lists. */ void initFonts () { Display display = shell.display; // get all fonts available on the current display addFonts (display.getFontList (null, false)); addFonts (display.getFontList (null, true)); setItemsSorted (charSetList, getFonts ()); if (fontData != null) { // verify that the initial font data is a valid font Font font = new Font (display, fontData); fontData = font.getFontData (); currentFontData = fontData [0]; font.dispose (); } else { fontData = display.textFont.getFontData (); currentFontData = fontData [0]; } } /** * Initialize the size list with the sizes the selected font * is available in. If the selected font is scalable a selection * of preset sizes is used. */ void initSizeList () { String oldSelect = getListSelection (fontSizeList); fontSizeList.removeAll (); String characterSet = getListSelection (charSetList); String faceName = getListSelection (faceNameList); String extStyle = getListSelection (extStyleList); Hashtable sizes = getSizes (characterSet, faceName, extStyle); if (sizes != null) { if (sizes.get (SCALABLE_KEY) == null) { /* * Font is not scalable so just present the provided sizes. */ setSizeItemsSorted (sizes.keys ()); } else { /* * Font is scalable so present the provided sizes and scalable * sizes for selection. */ Vector allSizes = new Vector (); /* * Add the scalable sizes. */ for (int i = 0; i < SCALABLE_SIZES.length; i++) { allSizes.addElement (Integer.valueOf (SCALABLE_SIZES [i])); } /* * Add the provided sizes. */ Enumeration providedSizes = sizes.keys (); while (providedSizes.hasMoreElements ()) { Integer size = (Integer) providedSizes.nextElement (); if (!size.equals (SCALABLE_KEY) && !allSizes.contains (size)) { allSizes.addElement (size); } } setSizeItemsSorted (allSizes.elements ()); } } int selectIndex = fontSizeList.indexOf (oldSelect); if (selectIndex == -1) { selectIndex = fontSizeList.indexOf (String.valueOf (DEFAULT_SIZE)); } selectIndex = Math.max (0, selectIndex); fontSizeList.select (selectIndex); fontSizeList.setData (new Integer (selectIndex)); centerListIndex (fontSizeList, selectIndex); initStyleList (); } /** * Initialize the styles list with the styles the selected font * is available in. */ void initStyleList () { String oldSelect = getListSelection (fontStyleList); fontStyleList.removeAll (); String characterSet = getListSelection (charSetList); String faceName = getListSelection (faceNameList); String extStyle = getListSelection (extStyleList); try { int size = Integer.valueOf (getListSelection (fontSizeList)).intValue (); if (size > 0) { Hashtable styles = getStyles (characterSet, faceName, extStyle, size); setItemsSorted (fontStyleList, styles); } } catch (NumberFormatException e) { // fall through } int selectIndex = fontStyleList.indexOf (oldSelect); if (selectIndex == -1) { selectIndex = fontStyleList.indexOf (String.valueOf (DEFAULT_STYLE)); } selectIndex = Math.max (0, selectIndex); fontStyleList.select (selectIndex); fontStyleList.setData (new Integer (selectIndex)); centerListIndex (fontStyleList, selectIndex); } /** * Makes the dialog visible and brings it to the front * of the display. * * @return a FontData object describing the font that was selected, * or null if the dialog was cancelled or an error occurred * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li> * </ul> */ public FontData open () { shell = new Shell (getParent (), getStyle () | SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL); shell.setLayout (new GridLayout ()); createControls (shell); FontData [] originalFontData = fontData; RGB originalRGB = rgb; initFonts (); openDialog (); setFontControls (currentFontData); updateSampleFont (); updateSampleColor (); updateFontList (); fontSetList.select (0); fontSetList.setData (new Integer (0)); updateButtonEnablements (); hookListeners (); Display display = shell.display; while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } FontData result = null; if (okSelected) { result = fontData [0]; } else { fontData = originalFontData; rgb = originalRGB; } if (sampleFont != null) sampleFont.dispose (); sampleFont = null; if (sampleColor != null) sampleColor.dispose (); sampleColor = null; return result; } /** * Open the receiver and set its size to the size calculated by * the layout manager. */ void openDialog () { // Start everything off by setting the shell size to its computed size. Point pt = shell.computeSize (SWT.DEFAULT, SWT.DEFAULT, false); // Ensure that the width of the shell fits the display. Display display = shell.display; Rectangle displayRect = display.getBounds (); int widthLimit = displayRect.width * 7 / 8; int heightLimit = displayRect.height * 7 / 8; if (pt.x > widthLimit) { pt = shell.computeSize (widthLimit, SWT.DEFAULT, false); } /* * If the parent is visible then center this dialog on it, * otherwise center this dialog on the parent's monitor */ Rectangle parentBounds = null; if (parent.isVisible ()) { parentBounds = getParent ().getBounds (); } else { parentBounds = parent.getMonitor ().getBounds (); } int originX = (parentBounds.width - pt.x) / 2 + parentBounds.x; originX = Math.max (originX, 0); originX = Math.min (originX, widthLimit - pt.x); int originY = (parentBounds.height - pt.y) / 2 + parentBounds.y; originY = Math.max (originY, 0); originY = Math.min (originY, heightLimit - pt.y); shell.setBounds (originX, originY, pt.x, pt.y); String title = getText (); if (title.length () == 0) title = SWT.getMessage ("SWT_FontDialog_Title"); shell.setText (title); // Open the window. shell.open (); } /** * Initialize the lists with the data of the preselected * font specified by the user. */ void setFontControls (FontData fontData) { ignoreEvents = true; String characterSet = getTranslatedCharSet (fontData, true); String faceName = getTranslatedFaceName (fontData); charSetList.select (new String[] {characterSet}); int index = charSetList.indexOf (characterSet); charSetList.setData (new Integer (index)); if (index != -1) centerListIndex (charSetList, index); initFaceNameList (); faceNameList.select (new String[] {faceName}); index = faceNameList.indexOf (faceName); faceNameList.setData (new Integer (index)); if (index != -1) centerListIndex (faceNameList, index); initExtStyleList (); extStyleList.select (new String[] {fontData.addStyle}); index = extStyleList.indexOf (fontData.addStyle); extStyleList.setData (new Integer (index)); if (index != -1) centerListIndex (extStyleList, index); initSizeList (); String value = String.valueOf (fontData.getHeight ()); fontSizeList.select (new String[] {value}); index = fontSizeList.indexOf (value); fontSizeList.setData (new Integer (index)); if (index != -1) centerListIndex (fontSizeList, index); initStyleList (); fontStyleList.select (new String[] {fontData.weight}); index = fontStyleList.indexOf (fontData.weight); fontStyleList.setData (new Integer (index)); if (index != -1) centerListIndex (fontStyleList, index); ignoreEvents = false; } /** * Sets a FontData object describing the font to be * selected by default in the dialog, or null to let * the platform choose one. * * @param fontData the FontData to use initially, or null * @deprecated use #setFontList (FontData []) */ public void setFontData (FontData fontData) { if (fontData == null) { this.fontData = null; } else { this.fontData = new FontData [1]; this.fontData [0] = fontData; } } /** * Sets the set of FontData objects describing the font to * be selected by default in the dialog, or null to let * the platform choose one. * * @param fontData the set of FontData objects to use initially, or null * to let the platform select a default when open() is called * * @see Font#getFontData * * @since 2.1.1 */ public void setFontList (FontData [] fontData) { this.fontData = fontData; } /** * Set the contents of 'list' to the keys of 'items'. * Keys are sorted in ascending order first and have to be Strings. */ void setItemsSorted (List list, Hashtable items) { if (items == null) return; Enumeration itemKeys = items.keys (); String [] sortedItems = new String [items.size ()]; int index = 0; while (itemKeys.hasMoreElements ()) { String item = (String) itemKeys.nextElement (); if (item.length () != 0) sortedItems [index++] = item; } if (index != sortedItems.length) { String [] newItems = new String [index]; System.arraycopy (sortedItems, 0, newItems, 0, index); sortedItems = newItems; } sort (sortedItems); list.setItems (sortedItems); } /** * Sets the RGB describing the color to be selected by default * in the dialog, or null to let the platform choose one. * * @param rgb the RGB value to use initially, or null to let * the platform select a default when open() is called * * @see PaletteData#getRGBs * * @since 2.1 */ public void setRGB (RGB rgb) { this.rgb = rgb; } /** * Set the contents of the size list to the keys of 'items'. * Keys are sorted in ascending order first and have to be Integers. */ void setSizeItemsSorted (Enumeration itemsEnum) { Vector items = new Vector (); while (itemsEnum.hasMoreElements ()) { items.addElement (itemsEnum.nextElement ()); } Integer [] sortedItems = new Integer [items.size ()]; items.copyInto (sortedItems); sort (sortedItems); String [] sortedItemStrings = new String [items.size ()]; for (int i = 0; i < sortedItemStrings.length; i++) { sortedItemStrings [i] = String.valueOf (sortedItems [i].intValue ()); } fontSizeList.setItems (sortedItemStrings); } /** * Sort 'items' in ascending order. */ void sort (Integer [] items) { /* Shell Sort from K&R, pg 108 */ int length = items.length; for (int gap = length / 2; gap > 0; gap /= 2) { for (int i = gap; i < length; i++) { for (int j = i - gap; j >= 0; j -= gap) { if (items [j].intValue () > items [j + gap].intValue ()) { Integer swap = items [j]; items [j] = items [j + gap]; items [j + gap] = swap; } } } } } /** * Sort 'items' in ascending order. */ void sort (String items []) { /* Shell Sort from K&R, pg 108 */ int length = items.length; for (int gap = length / 2; gap > 0; gap /= 2) { for (int i = gap; i < length; i++) { for (int j = i - gap; j >= 0; j -= gap) { if (items [j].compareTo (items [j + gap]) > 0) { String swap = items [j]; items [j] = items [j + gap]; items [j + gap] = swap; } } } } } void updateButtonEnablements () { removeButton.setEnabled (fontSetList.getItemCount () > 1); upButton.setEnabled (fontSetList.getSelectionIndex () > 0); downButton.setEnabled (fontSetList.getSelectionIndex () < fontSetList.getItemCount () - 1); } void updateFontList () { int selectionIndex = fontSetList.getSelectionIndex (); int topIndex = Math.max (0, fontSetList.getTopIndex ()); String [] items = new String [fontData.length]; for (int i = 0; i < fontData.length; i++) { StringBuffer buffer = new StringBuffer (); buffer.append (i); buffer.append (": "); buffer.append (getTranslatedCharSet (fontData [i], false)); buffer.append ("-"); buffer.append (getTranslatedFaceName (fontData [i])); buffer.append ("-"); if (!fontData [i].addStyle.equals ("")) { buffer.append (fontData [i].addStyle); buffer.append ("-"); } buffer.append (fontData [i].getHeight ()); buffer.append ("-"); buffer.append (fontData [i].weight); items [i] = buffer.toString (); } fontSetList.setItems (items); if (selectionIndex >= items.length) selectionIndex--; fontSetList.select (selectionIndex); fontSetList.setData (new Integer (selectionIndex)); fontSetList.setTopIndex (topIndex); fontSetList.showSelection (); } void updateSampleColor () { if (rgb == null) { rgb = new RGB (0, 0, 0); } if (sampleColor != null) { if (sampleColor.getRGB ().equals (rgb)) return; sampleColor.dispose (); } sampleColor = new Color (parent.display, rgb); sampleLabel.setForeground (sampleColor); } /** * Set the font of the sample text to the selected font. * Display an error in place of the sample text if the selected * font could not be loaded. */ void updateSampleFont () { FontData selectionFontData = getSelectionFontData (); /* * sampleFont may not be the same as the one specified in selectionFontData. * This happens when selectionFontData specifies a font alias. */ if (sampleFont != null) sampleFont.dispose (); int selectionIndex = Math.max (0, fontSetList.getSelectionIndex ()); fontData [selectionIndex] = selectionFontData; sampleFont = new Font (shell.display, selectionFontData); sampleLabel.setFont (sampleFont); } }